package com.kk.mybatis.service.Impl;

import com.alibaba.excel.EasyExcel;
import com.github.pagehelper.PageHelper;
import com.kk.mybatis.entity.Label;
import com.kk.mybatis.entity.Material;
import com.kk.mybatis.mapper.*;
import com.kk.mybatis.service.MaterialService;
import com.kk.mybatis.util.excelUtil.ExcelData;
import com.kk.mybatis.util.excelUtil.ExcelListener;
import com.kk.mybatis.util.excelUtil.LocalDateTimeConverter;
import org.mybatis.dynamic.sql.insert.render.MultiRowInsertStatementProvider;
import org.mybatis.dynamic.sql.render.RenderingStrategies;
import org.mybatis.dynamic.sql.select.render.SelectStatementProvider;
import org.mybatis.dynamic.sql.update.render.UpdateStatementProvider;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

import static java.util.stream.Collectors.groupingBy;
import static org.mybatis.dynamic.sql.SqlBuilder.*;

/**
 * @description:
 * @author: Kk
 * @create: 2020-11-27 11:35
 **/
@Service
public class MaterialServiceImpl implements MaterialService {

    @Resource
    private MaterialMapper materialMapper;
    @Resource
    private LabelMapper labelMapper;

    MaterialDynamicSqlSupport.Material material=MaterialDynamicSqlSupport.material;
    MaterialLabelRelDynamicSqlSupport.MaterialLabelRel materialLabelRel=MaterialLabelRelDynamicSqlSupport.materialLabelRel;
    LabelDynamicSqlSupport.Label label=LabelDynamicSqlSupport.label;

    /**
     * 分页查询对应标签下的素材
     * @param labelId
     * @param pageNum
     * @param limit
     * @return
     */
    @Override
    public List<Material> listMaterials(int labelId, int pageNum, int limit) {
        SelectStatementProvider statementProvider=select(material.allColumns())
                .from(materialLabelRel,"ml")
                .leftJoin(material,"m")
                .on(material.id,equalTo(materialLabelRel.id))
                .where(materialLabelRel.lId,isEqualTo(labelId))
                .and(materialLabelRel.status,isEqualTo(0))
                .and(material.status,isEqualTo(0))
                .orderBy(sortColumn("m.update_time").descending())
                .build().render(RenderingStrategies.MYBATIS3);
        PageHelper.startPage(pageNum,limit);
        List<Material> materials = materialMapper.selectMany(statementProvider);
        return materials;
        /*//统计该标签下的素材数量
        int count=materialMapper.countMaterialByLabelId(labelId);
        if (count==0){
            //若count为0，则直接返回
            return null;
        }else {
            //若count大于1，则获取结果集
            int startNum = (page - 1) * limit;
            List<Material> materials = materialMapper.selectMaterialByLabelId(labelId, startNum, limit);
            return materials;
        }*/
    }

    //递归查找叶子标签
    @Override
    public int countMaterial(int labelId) {
        int count=0;
        Set<Label> results=new HashSet<>();
        //查询子标签列表
        List<Label> children = labelMapper.selectLabelByPid(labelId);

        if (children.size()==0||children==null){
            //叶子标签则查询数量
            count+=materialMapper.countMaterialByLabelId(labelId);
        }else {
            findChildren(children,results);
            Iterator<Label> iterator = results.iterator();
            while (iterator.hasNext()){
                count+=materialMapper.countMaterialByLabelId(iterator.next().getId());
            }
        }

        return count;
    }

    //DFS
    private void findChildren(List<Label> children, Set<Label> results) {
        for(Label label:children){
            //寻找叶子结点
            List<Label> son = labelMapper.selectLabelByPid(label.getId());
            if (son.size()==0){
                //添加叶子结点标签
                results.add(label);
            }else {
                findChildren(son,results);
            }
        }
    }

    @Override
    public void saveExcel(MultipartFile file, MaterialService materialService) {
        try {
            InputStream in=file.getInputStream();
            //调用方法读取
            EasyExcel.read(in, ExcelData.class,new ExcelListener(materialService)).sheet().doRead();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 导出素材到excel
     * @param type
     */
    @Override
    public void exportExcel(int type) {
        List<Material> materials=null;
        if (type!=-1){
            materials=materialMapper.selectByType(type);
        }
        //type=-1,0,1,2
        materials=materialMapper.selectMany(select(material.allColumns()).from(material).where(material.status,isEqualTo(0)).build().render(RenderingStrategies.MYBATIS3));
        String path = System.getProperty("user.dir");
        DateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd hh-mm-ss");
        String n_date = dateFormat.format(new Date());
        String filePath=path+"/excelFile/";
        String fileName=n_date+".xlsx";
        //System.out.println(filePath);
        File file=new File(filePath+fileName);
        File dir=new File(filePath);
        if (!dir.exists()){
            dir.mkdir();
        }
        if (!file.exists()){
            try {
                System.out.println("create");
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        EasyExcel.write(file, Material.class).registerConverter(new LocalDateTimeConverter()).sheet("demo").doWrite(materials);
    }

    /**
     * 模糊查询
     * @param keyword
     * @param pageNum
     * @param limit
     * @return
     */
    @Override
    public Map<Integer, List<Material>> listMaterialsByKeyword(String keyword, int pageNum, int limit) {
        SelectStatementProvider statementProvider=
                select(material.id,material.title,material.type,material.url,material.description,material.score)
                .from(material)
                .where(material.title,isLike("%"+keyword+"%"))
                .or(material.description,isLike("%"+keyword+"%"))
                .and(material.status,isEqualTo(0))
                .orderBy(material.updateTime.descending())
                .build().render(RenderingStrategies.MYBATIS3);
        PageHelper.startPage(pageNum,limit);
        List<Material> materials = materialMapper.selectMany(statementProvider);
        Map<Integer, List<Material>> map=materials.stream().collect(groupingBy(Material::getType));
        return map;
    }


    /**
     * 批量插入
     * @param materials
     * @return
     */
    @Override
    public boolean saveBatch(List<Material> materials) {
        MultiRowInsertStatementProvider<Material> multiRowInsert  = insertMultiple(materials)
                .into(material)
                //.map(material.id).toProperty("id")
                .map(material.title).toProperty("title")
                .map(material.type).toProperty("type")
                .map(material.url).toProperty("url")
                .map(material.score).toProperty("score")
                .map(material.description).toProperty("description")
                .map(material.createTime).toProperty("createTime")
                .map(material.updateTime).toProperty("updateTime")
                .build().render(RenderingStrategies.MYBATIS3);
        //int rows = materialMapper.insertMultiple(multiRowInsert);
        int rows = materialMapper.insertMultipleWithGeneratedKeys(multiRowInsert);

        return rows==0?false:true;
    }

    @Override
    public void save(Material material) {
        materialMapper.insert(material);
    }

    @Override
    public boolean removeById(int mId) {
        //int i = materialMapper.deleteByPrimaryKey(mId);
        UpdateStatementProvider updateStatementProvider=update(material).set(material.status).equalTo(1)
                                                        .where(material.id,isEqualTo(mId))
                                                        .build()
                                                        .render(RenderingStrategies.MYBATIS3);
        int update = materialMapper.update(updateStatementProvider);
        return update==0?false:true;
    }

    @Override
    public boolean removeByIds(List<Integer> mIds) {
       /* DeleteStatementProvider deleteStatementProvider=deleteFrom(material)
                .where(material.id,isIn(mIds))
                .build()
                .render(RenderingStrategies.MYBATIS3);
        int delete = materialMapper.delete(deleteStatementProvider);*/

        //逻辑删除
        UpdateStatementProvider updateStatementProvider=update(material)
                .set(material.status).equalTo(1)
                .where(material.id,isIn(mIds))
                .build()
                .render(RenderingStrategies.MYBATIS3);
        int delete = materialMapper.update(updateStatementProvider);
        /*int count=0;
        mIds.stream().forEach(id -> {
             materialMapper.deleteByPrimaryKey(id);
        });*/
        return delete==0?false:true;
    }
}
